#include <crt_util.h>

#if (TARGET_OS == OS_WIN)

int _mutex_init(_mutex_t* lock)
{
    rc_error(lock != NULL, S_ERROR);
    InitializeCriticalSection(&lock->cs);
    lock->owner = 0;
    return 0;
}

int _mutex_init_recursive(_mutex_t* lock)
{
    rc_error(lock != NULL, S_ERROR);
    return _mutex_init(lock);
}

int _mutex_destroy(_mutex_t* lock)
{
    rc_error(lock != NULL, S_ERROR);
    DeleteCriticalSection(&lock->cs);
    lock->owner = 0;
    return S_SUCCESS;
}

int _mutex_trylock(_mutex_t* lock)
{
    rc_error(lock != NULL, S_ERROR);
    BOOL rc = TryEnterCriticalSection(&lock->cs) > 0 ? 0 : -1;
    if (rc)
        lock->owner = GetCurrentThreadId();
    return rc;
}

int _mutex_lock(_mutex_t* lock)
{
    rc_error(lock != NULL, S_ERROR);
    EnterCriticalSection(&lock->cs);
    lock->owner = GetCurrentThreadId();
    return S_SUCCESS;
}
int _mutex_unlock(_mutex_t* lock)
{
    LeaveCriticalSection(&lock->cs);
    lock->owner = 0;
    return S_SUCCESS;
}

#elif (TARGET_OS == OS_POSIX)

int _mutex_init(_mutex_t* lock)
{
    rc_error(lock != NULL, S_ERROR);
    if (pthread_mutex_init(&lock->mutex, NULL)) {
        return S_ERROR;
    }
    return S_SUCCESS;
}

int _mutex_init_recursive(_mutex_t* lock)
{
    rc_error(lock != NULL, S_ERROR);
    pthread_mutexattr_t attr;

    if (pthread_mutexattr_init(&attr)) {
        return S_ERROR;
    }

    if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)) {
        return S_ERROR;
    }

    if (pthread_mutex_init(&lock->mutex, &attr)) {
        return S_ERROR;
    }

    if (pthread_mutexattr_destroy(&attr)) {
        return S_ERROR;
    }

    return S_SUCCESS;
}

int _mutex_destroy(_mutex_t* lock)
{
    rc_error(lock != NULL, S_ERROR);
    if (pthread_mutex_destroy(&lock->mutex)) {
        return S_ERROR;
    }
    return S_SUCCESS;
}

int _mutex_lock(_mutex_t* lock)
{
    rc_error(lock != NULL, S_ERROR);
    if (pthread_mutex_lock(&lock->mutex)) {
        return S_ERROR;
    }
    return S_SUCCESS;
}

int _mutex_trylock(_mutex_t* lock)
{
    rc_error(lock != NULL, S_ERROR);
    if (pthread_mutex_trylock(&lock->mutex)) {
        return S_ERROR;
    }
    return S_SUCCESS;
}

int _mutex_unlock(_mutex_t* lock)
{
    rc_error(lock != NULL, S_ERROR);
    if (pthread_mutex_unlock(&lock->mutex)) {
        return S_ERROR;
    }
    return S_SUCCESS;
}

#elif (TARGET_OS == OS_MACH)

int _mutex_init(_mutex_t* lock)
{
    rc_error(lock != NULL, S_ERROR);
    if (pthread_mutex_init(&lock->mutex, NULL)) {
        return S_ERROR;
    }

    return S_SUCCESS;
}

int _mutex_init_recursive(_mutex_t* lock)
{
    rc_error(lock != NULL, S_ERROR);
    pthread_mutexattr_t attr;

    if (pthread_mutexattr_init(&attr)) {
        return S_ERROR;
    }

    if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)) {
        return S_ERROR;
    }

    if (pthread_mutex_init(&lock->mutex, &attr)) {
        return S_ERROR;
    }

    if (pthread_mutexattr_destroy(&attr)) {
        return S_ERROR;
    }

    return S_SUCCESS;
}

int _mutex_destroy(_mutex_t* lock)
{
    rc_error(lock != NULL, S_ERROR);
    if (pthread_mutex_destroy(&lock->mutex)) {
        return S_ERROR;
    }

    return S_SUCCESS;
}

int _mutex_lock(_mutex_t* lock)
{
    rc_error(lock != NULL, S_ERROR);
    if (pthread_mutex_lock(&lock->mutex)) {
        return S_ERROR;
    }

    return S_SUCCESS;
}

int _mutex_trylock(_mutex_t* lock)
{
    rc_error(lock != NULL, S_ERROR);
    if (pthread_mutex_trylock(&lock->mutex)) {
        return S_ERROR;
    }

    return S_SUCCESS;
}

int _mutex_unlock(_mutex_t* lock)
{
    rc_error(lock != NULL, S_ERROR);
    if (pthread_mutex_unlock(&lock->mutex)) {
        return S_ERROR;
    }

    return S_SUCCESS;
}

#elif (TARGET_OS == OS_UNIX)

int _mutex_init(_mutex_t* lock)
{
    rc_error(lock != NULL, S_ERROR);
    if (pthread_mutex_init(&lock->mutex, NULL)) {
        return S_ERROR;
    }
    return S_SUCCESS;
}

int _mutex_init_recursive(_mutex_t* lock)
{
    rc_error(lock != NULL, S_ERROR);
    pthread_mutexattr_t attr;

    if (pthread_mutexattr_init(&attr)) {
        return S_ERROR;
    }

    if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)) {
        return S_ERROR;
    }

    if (pthread_mutex_init(&lock->mutex, &attr)) {
        return S_ERROR;
    }

    if (pthread_mutexattr_destroy(&attr)) {
        return S_ERROR;
    }

    return S_SUCCESS;
}

int _mutex_destroy(_mutex_t* lock)
{
    rc_error(lock != NULL, S_ERROR);
    if (pthread_mutex_destroy(&lock->mutex)) {
        return S_ERROR;
    }
    return S_SUCCESS;
}

int _mutex_lock(_mutex_t* lock)
{
    rc_error(lock != NULL, S_ERROR);
    if (pthread_mutex_lock(&lock->mutex)) {
        return S_ERROR;
    }
    return S_SUCCESS;
}

int _mutex_trylock(_mutex_t* lock)
{
    rc_error(lock != NULL, S_ERROR);
    if (pthread_mutex_trylock(&lock->mutex)) {
        return S_ERROR;
    }
    return S_SUCCESS;
}

int _mutex_unlock(_mutex_t* lock)
{
    rc_error(lock != NULL, S_ERROR);
    if (pthread_mutex_unlock(&lock->mutex)) {
        return S_ERROR;
    }
    return S_SUCCESS;
}

#endif
